#include <assert.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include "./include/ipc.h"

/*
 * 向系统申请共享内存
 * 返回共享内存id
 */
int get_shm(const int key)
{
    //
    // 系统调用
    //
    int shmid = shmget( (key_t)key, sizeof(shmd_t), IPC_CREAT|0666 );
    assert(-1 != shmid);
    return shmid;
}

/*
 * 向绑定共享内存到进程地址空间
 * 返回共享内存的起始地址
 */
void* attach_shm(const int shmid)
{
    assert(shmid > 0);
    //
    // 系统调用
    //
    void* shmd_ptr = shmat(shmid, 0, 0);
    assert((void *)-1 != shmd_ptr);
    return shmd_ptr;
}

/*
 * 初始化共享内存中的数据
 */
void init_shm(void* ptr, const int num)
{
    assert( ptr && num > 0 );
    shmd_t *shmd_ptr = (shmd_t*)ptr;
    for(int i=0; i<BUFFER_SIZE; i++) {
        shmd_ptr->buffer[i] = 0;
    }
    shmd_ptr->c = 0;
    shmd_ptr->p = 0;
    shmd_ptr->num = 0;
    shmd_ptr->p_speed = 1000;  // 初始速率为 1 秒
    shmd_ptr->c_speed = 1000;  // 初始速率为 1 秒
}

/*
 * 释放共享内存空间
 */
void free_shm(const void* shmd_ptr, const int shmid)
{
    assert(shmid > 0);
    //
    // 系统调用
    // 将解除绑定
    //
    assert( -1 != shmdt(shmd_ptr) );
    //
    // 系统调用
    // 释放共享内存空间
    //
    assert( -1 != shmctl(shmid, IPC_RMID, 0) );
}

/*
 * 打印共享内存数据
 */
void show_shm(int (*output)(const char * fm, ...), void* ptr)
{
    assert(ptr );
    shmd_t *shmd_ptr = (shmd_t*)ptr;
    output("  shm buffer: \n  ");
    for(int i=1; i<=BUFFER_SIZE; i++) {
        output("%-4d",shmd_ptr->buffer[i-1]);
        output("%c  ", (0 == i % 10) ? '\n' : ' ');
    }
    output("  p = %d, c = %d\n", shmd_ptr->p, shmd_ptr->c);
    output("  buffer_size = %d, num = %d\n", BUFFER_SIZE, shmd_ptr->num);
    output("  p_speed = %d, c_speed = %d\n", shmd_ptr->p_speed, shmd_ptr->c_speed);
}

/////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////                    ///////////////////////////////////////////////
//////////////////////////////////     信号量接口       ///////////////////////////////////////////////
//////////////////////////////////                    ///////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////

/*
 * 向系统申请信号量
 * 返回信号量id
 */
int get_sem(const int key)
{
    //
    // 系统调用 semget
    //
    int semid = semget((key_t)key, 1, IPC_CREAT|0666);
    assert(-1 != semid );
    return semid;
}

/*
 * 初始化信号量
 */
void init_sem(const int semid, const int val)
{
    assert(-1 != semid);

    union semun {
        int val;
        struct semid_ds* buf;
        unsigned short *arry;
    } arg;

    arg.val = val;

    //
    // 系统调用 semctl
    //
    assert( -1 != semctl(semid, 0, SETVAL, arg) );
}

/*
 * 信号量pv操作
 * 由参数op决定
 */
void sem_pv(const int semid, const int op)
{
    assert( semid != -1 && (-1 == op || 1 == op) );

    struct sembuf sops;
    sops.sem_num = 0;
    sops.sem_op = op;
    sops.sem_flg = SEM_UNDO;

    //
    // 系统调用 semop
    //
    assert( -1 != semop(semid, &sops, 1) );
}

/*
 * 释放系统的信号量
 */
void free_sem(const int semid)
{
    assert(-1 != semid );
    //
    // 系统调用 semctl
    //
    assert( -1 != semctl(semid, 0, IPC_RMID) );
}

